package com.lyc.lojbackendjudgeservice.rabbitmq;

import com.lyc.lojbackendcommon.common.ErrorCode;
import com.lyc.lojbackendcommon.exception.BusinessException;
import com.lyc.lojbackendjudgeservice.judge.JudgeService;
import com.lyc.lojbackendmodel.model.entity.Question;
import com.lyc.lojbackendmodel.model.entity.QuestionSubmit;
import com.lyc.lojbackendmodel.model.enums.QuestionSubmitStatusEnum;
import com.lyc.lojbackendserviceclient.service.QuestionFeignClient;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;

import static com.lyc.lojbackendcommon.config.RabbitmqConfig.QUEUE_CODE;


/**
 * rabbitmq 消费者
 */
@Component
@Slf4j
public class CodeMqConsumer {

    @Resource
    private JudgeService judgeService;

    @Resource
    private QuestionFeignClient questionFeignClient;


    /**
     * 指定程序监听的消息队列和确认机制
     *
     * @param message
     * @param channel
     * @param deliveryTag
     */
    @SneakyThrows
    @Retryable(value = { BusinessException.class }, maxAttempts = 3, backoff = @Backoff(delay = 1000))
    @RabbitListener(queues = {QUEUE_CODE}, ackMode = "MANUAL", concurrency = "2")
    private void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("接收到消息 ： {}", message);
        long questionSubmitId = Long.parseLong(message);
        try {
            // 有消息后判题服务根据题目提交id进行判题
            judgeService.doJudge(questionSubmitId);
            QuestionSubmit questionSubmit = questionFeignClient.getQuestionSubmitById(questionSubmitId);
            if (!questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.SUCCEED.getValue())) {
                // 进入死信队列
                channel.basicNack(deliveryTag, false, false);
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "判题失败");
            }
            log.info("新提交的信息：" + questionSubmit);
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
        } catch (IOException e) {
            // 消息为空，则拒绝消息，进入死信队列
            channel.basicNack(deliveryTag, false, false);
            throw new RuntimeException(e);
        }
    }
}
